package service

import (
	"encoding/json"
	"fmt"
	"strings"

	"lucidity.note/app/common"
	"lucidity.note/app/common/bean"
	"lucidity.note/app/common/db"
	"lucidity.note/app/common/logger"
)

type NotebookService struct{}

// 新建笔记本服务
// @param notebook {*Notebook} 笔记本参数
func (*NotebookService) NewNotebookService(notebook *bean.Notebook) error {
	isEndBySlash := strings.HasSuffix(notebook.Path, "/")
	if isEndBySlash {
		notebook.Path = notebook.Path[:len(notebook.Path)-1]
	}

	// step1: 判断是否联网, 初次创建必须联网
	isConn := common.NetWorkStatus()
	if !isConn {
		return fmt.Errorf("新建[%s]笔记本失败: 没有连接网络", notebook.Name)
	}

	// step2: 远程仓库克隆
	localPath := fmt.Sprintf("%s/%s", notebook.Path, notebook.Name)
	if repository, err := GitRepositoryClone(localPath, notebook.Username, notebook.Password, notebook.SyncAddr); nil != err {
		logger.FAULT.Printf("克隆远程仓库[%s]失败: => %s.", notebook.SyncAddr, err.Error())
		return fmt.Errorf("克隆远程仓库[%s]失败", notebook.SyncAddr)
	} else {
		if err := GitRepositoryPull(repository, "origin", notebook.Username, notebook.Password); nil != err {
			logger.FAULT.Printf("拉取远程仓库[%s]失败: => %s.", notebook.SyncAddr, err.Error())
		}
	}

	// step3: 初始化到数据库中
	conn := db.GetDiskInxNustDB()
	if jsonstr, err := json.Marshal(notebook); nil != err {
		logger.FAULT.Printf("新建笔记本[%s]失败: 笔记本信息序列化失败，错误详情{%s}", notebook.Name, err.Error())
		return fmt.Errorf("新建笔记本[%s]失败: 笔记本信息序列化失败", notebook.Name)
	} else {
		if err := conn.Insert(bean.GetNustDBBucketOfNotebook(), notebook.ID, string(jsonstr)); nil != err {
			logger.FAULT.Printf("新建笔记本[%s]失败: 笔记本入库失败，错误详情{%s}", notebook.Name, err.Error())
			return fmt.Errorf("新建笔记本[%s]失败: 笔记本入库失败", notebook.Name)
		}
	}
	return nil
}

// 查询所有的笔记本信息
func (*NotebookService) GetAllNotebookService() (notebooks []*bean.Notebook, err error) {
	notebooks = make([]*bean.Notebook, 0)
	conn := db.GetDiskInxNustDB()
	if entries, e := conn.GetAll(bean.GetNustDBBucketOfNotebook()); nil != e {
		var message = e.Error()
		if strings.EqualFold("bucket is empty", message) {
			message = "暂无笔记本信息，请新增笔记本"
		}
		err = fmt.Errorf("获取所有笔记本失败: 错误详情{%s}", message)
	} else {
		for _, value := range entries {
			// 将 value 反序列化成 notebook 结构体对象
			var notebook bean.Notebook
			if e := json.Unmarshal([]byte(value), &notebook); nil != e {
				err = fmt.Errorf("笔记本json串信息序列化失败: 错误详情{%s}", e.Error())
				break
			} else {
				notebooks = append(notebooks, &notebook)
			}
		}
	}
	return notebooks, err
}

// 根据笔记本ID查询对应的笔记本
func (*NotebookService) GetNotebookByIdService(notebookId string) (notebook *bean.Notebook, err error) {
	conn := db.GetDiskInxNustDB()
	if value, e := conn.Select(bean.GetNustDBBucketOfNotebook(), notebookId); nil != e {
		err = fmt.Errorf("查询{ID=%s}笔记本失败: 错误详情{%s}", notebookId, e.Error())
	} else if common.IsBlank(value) {
		err = fmt.Errorf("查询{ID=%s}笔记本失败: 错误详情，查出的笔记本数据为空", notebookId)
	} else {
		var nb bean.Notebook = bean.Notebook{}
		if e := json.Unmarshal([]byte(value), &nb); nil != e {
			err = fmt.Errorf("笔记本json串信息序列化失败: 错误详情{%s}", e.Error())
		} else {
			notebook = &nb
		}
	}
	return notebook, err
}

// 笔记本更新
func (*NotebookService) UpdateNotebookService(notebook *bean.Notebook) error {
	client := CreateWebdavClientInstance(notebook.Username, notebook.Password, notebook.SyncAddr)

	if file, err := client.Stat(notebook.Name); nil != err {
		var errMsg = fmt.Sprintf("PROPFIND /%s/: 404", notebook.Name)
		if strings.EqualFold(errMsg, err.Error()) {
			// 新建本地文件,然后推送远程
		} else {
			logger.FAULT.Println(err.Error())
			return err
		}
	} else {
		// 有文件,将远程文件同步到本地
		logger.FAULT.Println(file.Name())
	}

	conn := db.GetDiskInxNustDB()
	if jsonstr, err := json.Marshal(notebook); nil != err {
		return fmt.Errorf("更新笔记本失败: 笔记本信息序列化失败，错误详情{%s}", err.Error())
	} else {
		if err := conn.Update(bean.GetNustDBBucketOfNotebook(), notebook.ID, string(jsonstr)); nil != err {
			return fmt.Errorf("更新笔记本失败: 笔记本入库失败，错误详情{%s}", err.Error())
		}
	}
	return nil
}

// WEBDAV 同步模式
// func (*NotebookService) NewNotebookService(notebook *bean.Notebook) error {
// 	// step1: 先创建本地文件夹
// 	isEndBySlash := strings.HasSuffix(notebook.Path, "/")
// 	if isEndBySlash {
// 		notebook.Path = notebook.Path[:len(notebook.Path)-1]
// 	}

// 	// 拼接本地笔记本路径
// 	isCreateDir := false
// 	localPath := fmt.Sprintf("%s/%s", notebook.Path, notebook.Name)
// 	if exist, err := common.PathExists(localPath); nil != err {
// 		err = fmt.Errorf("检查文件路径失败: 可能是文件夹权限问题[%s]", err.Error())
// 		logger.FAULT.Println(err.Error())
// 		return err
// 	} else if !exist {
// 		if err := os.Mkdir(localPath, os.ModePerm); nil != err {
// 			logger.FAULT.Printf("创建文件夹路径[%s]失败: %s\n", localPath, err.Error())
// 			err = fmt.Errorf("创建文件夹路径[%s]失败", localPath)
// 			return err
// 		}
// 		isCreateDir = true
// 	}

// 	// step2: 至此笔记本的本地文件夹创建成功,判断联网状态,是否需要从远程Wendav拉取文件初始化
// 	isConn := true
// 	client := CreateWebdavClientInstance(notebook.Username, notebook.Password, notebook.SyncAddr)
// 	file, err := client.Stat(notebook.Name)
// 	if nil != err {
// 		// 如果此处有错误,可能是两个原因,第一是因为网络问题,还有就是文件路径不存在,因此首先第一遇到错误之后,直接创建文件夹
// 		err := client.MkdirAll(notebook.Name, 0644)
// 		if nil != err {
// 			// 此时的问题可能就是网络问题,导致产生无法处理,因此先记录问题
// 			errMsg := fmt.Sprintf("创建远程[%s]的[%s]文件夹失败, 失败原因:%s", notebook.Path, notebook.Name, err.Error())
// 			logger.FAULT.Printf(errMsg)
// 			isConn = common.NetWorkStatus()
// 			if isConn {
// 				// 如果网络状态正常报错,则将错误抛出,终止笔记本的创建
// 				if isCreateDir { // 如果是本次创建的文件夹就进行移除
// 					os.RemoveAll(localPath)
// 				}
// 				return fmt.Errorf(errMsg)
// 			}
// 		}
// 	}

// 	// step3: 走到此处则说明本地文件夹创建成功, 网络状态通过 isConn 判断
// 	if nil != file && isConn {
// 		// 表示在远程存在此文件夹, 将远程的文件同步下来
// 		go DownloadToLocal(notebook.Path, notebook.Name, client)
// 	}

// 	// step4: 初始化到数据库中
// 	conn := db.GetDiskInxNustDB()
// 	if jsonstr, err := json.Marshal(notebook); nil != err {
// 		logger.FAULT.Printf("新建笔记本[%s]失败: 笔记本信息序列化失败，错误详情{%s}", notebook.Name, err.Error())
// 		return fmt.Errorf("新建笔记本[%s]失败: 笔记本信息序列化失败", notebook.Name)
// 	} else {
// 		if err := conn.Insert(NOTEBOOK_BUCKET, notebook.ID, string(jsonstr)); nil != err {
// 			logger.FAULT.Printf("新建笔记本[%s]失败: 笔记本入库失败，错误详情{%s}", notebook.Name, err.Error())
// 			return fmt.Errorf("新建笔记本[%s]失败: 笔记本入库失败", notebook.Name)
// 		}
// 	}
// 	return nil
// }
